package com.web_bloks.content.client;

import java.util.HashMap;

//import com.google.gwt.core.client.GWT;
import com.web_bloks.document.client.NamespaceException;
import com.web_bloks.document.client.Title;
import com.web_bloks.document.client.TitleException;
import com.web_bloks.user.client.User;
import com.web_bloks.system.client.Logger;

/**
 * - Condition to 'enter' a view [condition for view_x]
 * - 'Next view' from a view     [view_x => view_y]
 * 
 * Make sure to call 'doFinalInit' before using.
 * 
 * @author Jean-Lou Dupont
 *
 */
abstract public class FlowManager {

	/**
	 * FlowManager Response class
	 */
	public final class Response {
		ViewPage vp   = null;
		ResponseCode cc = null;
		ConditionCode cacl = null;
		protected Response() {}
		
		public ResponseCode getConditionCode() {
			return cc;
		}
		public ViewPage getContentPage() {
			return vp;
		}
	}//END

	public enum ResponseCode {
		NORMAL, WILD, DEFAULT, NOT_FOUND
	}
	
	HashMap<String, String> flow = null;
	TitleAccessList tacl = null;

	User currentUser = null;
	ViewManager vm = null;
	ConditionChecker cc = null;
	
	/*****************************************
	 * CONSTRUCTOR
	 *****************************************/
	protected FlowManager() {
		flow = new HashMap<String, String>();
	}
	/*****************************************
	 * CONFIGURATION
	 *****************************************/
	public void addNext(String page, String nextPage) {
		flow.put( page, nextPage );
	}
	public void setCurrentUser(User current) {
		currentUser = current;
	}
	public void setViewManager(ViewManager vm) {
		this.vm = vm;
	}
	public void setConditionChecker(ConditionChecker cc) {
		this.cc = cc;
	}
	public void setTitleAccessList(TitleAccessList tacl) {
		this.tacl = tacl;
	}
	/**
	 * Once all other configuration is done,
	 * call this method to bind everything together.
	 */
	public void doFinalInit() {
		
		if (null==cc || null==vm)
			throw new RuntimeException( this.getClass()+".doFinalInit: CONFIGURATION error");
		
		this.cc.setCurrentUser(currentUser);
	}
	/*****************************************
	 * API
	 *****************************************/
	/**
	 * Returns the configured ContentPage 
	 * associated with the page name.
	 * Verifies that all the conditions for allowing the user to 
	 * reach this page are met.
	 */
	public Response getPage(String page) throws TitleException, NamespaceException  {

		if (null == page)
			throw new RuntimeException( this.getClass() + ".getPage: page can't be null" );
		
		Logger.logDebug(this.getClass()+".getPage: page="+page);
		
		return process(page);
	}
	
	public Response getNext(String currentPage) throws TitleException, NamespaceException {
	
		if (null == currentPage)
			throw new RuntimeException( this.getClass() + ".getNext: currentPage can't be null" );

		Logger.logDebug(this.getClass()+".getNext: currentpage="+currentPage);
		
		Response rep = new FlowManager.Response();
		
		if (!flow.containsKey( currentPage )) {
			rep.cc = ResponseCode.NOT_FOUND;
		}

		String nextPage = flow.get( currentPage );
		
		return process(nextPage);
	}//
	
	protected Response process(String page) throws TitleException, NamespaceException {
		Response rep = new FlowManager.Response();
		
		Title title = Title.newFromText( page );
		
		ViewManager.Response vmr = vm.findMatch(title);

		if ( null == vmr )
			throw new RuntimeException(this.getClass()+".process: ViewManager["+vm.getClass()+"] is missing a 'wild' default");
		
		// ViewManager's response code includes:
		//  Response object : ResponseCode & ContentPage
		if ( vmr.getResponseCode() == ViewManager.ResponseCode.NOT_FOUND ) {
			rep.cc = ResponseCode.NOT_FOUND;
			return rep;
		} // anything else is OK
		
		// Check the 'entry condition' for the target page
		Condition[] conditions = tacl.findMatch(title);
		
		ConditionCode result = cc.verify(conditions);
		
		rep.cc   = mapResponseCodeFromViewManager( vmr.rc );
		rep.cacl = result;
		rep.vp   = vmr.getViewPage();
		
		return rep;
	}
	
	/*****************************************
	 * HELPERS
	 *****************************************/
	protected ResponseCode mapResponseCodeFromViewManager(ViewManager.ResponseCode vrc) {
		
		ResponseCode code = ResponseCode.NORMAL;
		
		switch( vrc) {
		case NORMAL:
			code = ResponseCode.NORMAL;
			break;
		case WILD:
			code = ResponseCode.WILD;
			break;
		case DEFAULT:
			code = ResponseCode.DEFAULT;
			break;
		case NOT_FOUND:
			code = ResponseCode.NOT_FOUND;
			break;
		}
		
		return code;
	}
	
}//END